package com.multi.thread;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class CountDownLatchDemo {
    public static void main(String[] args) throws Exception {
        test();
    }

    public static void test () throws Exception {
        List<String> list = new ArrayList<>();

        Random random = new Random();
        for (int i = 0; i < 100000; i++) {
            list.add(String.valueOf(i) + random.nextInt(100));
        }

        CountDownLatch countDownLatch = new CountDownLatch(list.size());

        ExecutorService executorService = Executors.newFixedThreadPool(10);

        list.forEach(item -> {
            executorService.execute(() -> {
                try{
                    System.out.println("处理数据: " + item + "，线程名：" + Thread.currentThread().getName());
                } catch (Exception e) {
                    e.printStackTrace();

                } finally {
                    countDownLatch.countDown();
                }
            });

        });

        countDownLatch.await();

        // 正确关闭方式1
        executorService.shutdown();
        while (!executorService.awaitTermination(500, TimeUnit.MILLISECONDS)) {
            System.out.println("线程池未在500毫秒内完全终止，继续等待...");
        }

        // 正确关闭方式2
        /*executorService.shutdown();
        for (;;) {

            // 返回 true：表示线程池在等待的 500 毫秒内已经完全终止（所有任务都执行完毕，线程池关闭）。
            // 返回 false：表示线程池在等待的 500 毫秒内没有完全终止（还有任务在执行，线程池未关闭）。
            if (executorService.awaitTermination(500, TimeUnit.MILLISECONDS)) {
                break;
            }
            System.out.println("线程池未在500毫秒内完全终止，继续等待...");
        }*/

        // 正确关闭方式3
        /*executorService.shutdown();
        for (; !executorService.awaitTermination(500, TimeUnit.MILLISECONDS); ) {
            System.out.println("线程池未在500毫秒内完全终止，继续等待...");
        }*/

        // 正确关闭方式4
        /*executorService.shutdown();
        try {
            // 等待线程池终止，最多等待1分钟
            if (!executorService.awaitTermination(1, TimeUnit.MINUTES)) {
                System.out.println("线程池未在指定时间内完全终止");
                executorService.shutdownNow(); // 强制关闭
            }
        } catch (InterruptedException e) {
            executorService.shutdownNow();
            Thread.currentThread().interrupt();
        }*/

        // 正确关闭方式5
        /*// 会发起线程池的关闭流程，拒绝新任务，但不会等待已有任务完成。
        executorService.shutdown();
        // 会让当前线程阻塞，直到线程池所有任务完成或超时，这样可以确保所有任务都执行完毕后再继续后续操作。
        executorService.awaitTermination(1, TimeUnit.MINUTES);*/

        System.out.println("所有任务完成，主线程继续执行。" + Thread.currentThread().getName());
    }

    public static void problem1() throws InterruptedException {
        List<String> list = new ArrayList<>();

        Random random = new Random();
        for (int i = 0; i < 100000; i++) {
            list.add(String.valueOf(i) + random.nextInt(100));
        }


        // 注意一个点，CountDownLatch 计数过大：CountDownLatch 的计数器设置为 100,000，会占用较多内存，不适合大规模任务。
        // 可以考虑使用其他并发工具，如 CyclicBarrier 或 Semaphore，或者将任务拆分成更小的批次来处理。
        CountDownLatch countDownLatch = new CountDownLatch(list.size());

        ExecutorService executorService = Executors.newFixedThreadPool(10);

        list.forEach(item -> {
            executorService.execute(() -> {
                try{

                    TimeUnit.SECONDS.sleep(random.nextInt(5));

                    System.out.println("处理数据: " + item + "，线程名：" + Thread.currentThread().getName());
                } catch (Exception e) {
                    e.printStackTrace();

                } finally {
                    countDownLatch.countDown();
                }
            });

        });

        countDownLatch.await();
        // 线程池关闭不正确，使用了shutdown()但没有等待线程池完全终止，可能导致主线程退出时还有任务在执行
        // 如果只调用 shutdown()，主线程会继续往下执行，可能导致资源提前释放或程序提前退出，部分任务还没执行完。
        // 配合 awaitTermination() 能保证线程池里的任务都处理完毕，关闭流程更安全、规范。
        executorService.shutdown(); // ❌

        System.out.println("所有任务完成，主线程继续执行。" + Thread.currentThread().getName());
    }
}
